package queue

import (
	"errors"
	"fmt"
)

/**
CircleQueue 环形队列
思路：
1.将数组看成是一个环形的（通过取模的方式来实现）
2.什么时候表示队列满 （tail+1）%maxSize==head
3.当tail==head时表示队列为空
4.初始化时，tail=0,head=0
4.统计该队列有多少个元素 (tail+maxSize-head)%maxSize
5.tail在队列尾部，不包含最后的元素（见下面的‘注意’），head指向队首并且含队首元素
*/

type CircleQueue struct {
	maxSize int    //
	array   [5]int //数组
	head    int    //指向队列队首
	tail    int    //指向队列队尾
}

func NewCircleQueue(num int) *CircleQueue {
	return &CircleQueue{
		maxSize: num,
		head:    0,
		tail:    0,
	}
}

//入队列
func (this *CircleQueue) Enqueue(val int) (err error) {
	if this.IsFull() {
		return errors.New("队列满了")
	}
	//this.tail在队列尾部，但是不包含最后的元素
	this.array[this.tail] = val
	this.tail = (this.tail + 1) % this.maxSize
	return
}

//出队列
func (this *CircleQueue) Dequeue() (val int, err error) {
	if this.IsEmpty() {
		return 0, errors.New("队列是空的")
	}
	//取出,head指向队首并且含队首元素
	val = this.array[this.head]
	this.head = (this.head + 1) % this.maxSize
	return
}

//显示队列
func (this *CircleQueue) ListQueue() {
	fmt.Println("环形队列情况如下")
	//取出当前队列有多少个元素
	size := this.Size()
	if size == 0 {
		fmt.Println("队列为空")
	}
	//设计一个辅助变量，指向head
	tempHead := this.head
	for i := 0; i < size; i++ {
		fmt.Printf("arr[%d]=%d\t", tempHead, this.array[tempHead])
		tempHead = (tempHead + 1) % this.maxSize
	}
	fmt.Println()
}

//判断环形队列为满
func (this *CircleQueue) IsFull() bool {
	return (this.tail+1)%this.maxSize == this.head
}

//判断队列是否为空
func (this *CircleQueue) IsEmpty() bool {
	return this.tail == this.head
}

//环形队列有多少个元素
func (this *CircleQueue) Size() int {
	//重要：一定要看
	//环形队列，head在不停的增长，快出去的时候加了一个maxSize，又拐回来，所以tail
	//某个情况下，自然值是小于head的，因此tail需要+maxSize再-head，然后再对maxSize取模
	return (this.tail + this.maxSize - this.head) % this.maxSize
}
